package utils

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"go-chain-data/global"
	"math/big"
	"strings"
)

// IsSwapV2Event 检查给定的日志是否表示swap事件。
func IsSwapV2Event(log *types.Log) bool {
	// 这是Swap事件的签名字符串
	swapEventSignature := []byte("Swap(address,uint256,uint256,uint256,uint256,address)")
	// 计算签名的Keccak-256哈希
	swapEventHash := crypto.Keccak256Hash(swapEventSignature)
	// 检查日志的第一个Topic是否等于Swap事件的哈希
	return log.Topics[0] == swapEventHash
}

// IsSwapV3Event 检查给定的日志是否表示swap事件。
func IsSwapV3Event(log *types.Log) bool {
	// 这是Swap事件的签名字符串
	swapEventSignature := []byte("Swap(address,address,int256,int256,uint160,uint128,int24,uint128,uint128)")
	// 计算签名的Keccak-256哈希
	swapEventHash := crypto.Keccak256Hash(swapEventSignature)
	// 检查日志的第一个Topic是否等于Swap事件的哈希
	return log.Topics[0] == swapEventHash
}

// CallContractMethod 通用函数，调用以太坊合约的只读方法
func CallContractMethod(contractAddress common.Address, contractABI string, methodName string, params ...interface{}) ([]interface{}, error) {
	// 解析合约ABI
	parsedABI, err := abi.JSON(strings.NewReader(contractABI))
	if err != nil {
		return nil, fmt.Errorf("failed to parse contract ABI: %v", err)
	}

	// 打包合约调用数据
	packedData, err := parsedABI.Pack(methodName, params...)
	if err != nil {
		return nil, fmt.Errorf("failed to pack data for method %s: %v", methodName, err)
	}

	callMsg := ethereum.CallMsg{
		To:   &contractAddress,
		Data: packedData,
	}

	// 调用合约
	ctx := context.Background()
	result, err := global.EthRpcClient.CallContract(ctx, callMsg, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to call contract method %s: %v", methodName, err)
	}

	// 解包合约调用结果
	outputs, err := parsedABI.Unpack(methodName, result)
	if err != nil {
		return nil, fmt.Errorf("failed to unpack return data for method %s: %v", methodName, err)
	}

	return outputs, nil
}

// WeiBigIntToEtherStr 将Wei的*big.Int转换为Ether的字符串形式
func WeiBigIntToEtherStr(wei *big.Int, decimals uint8) string {
	// 计算代币单位，即1 Ether等于10的decimals次方Wei
	tokenUnit := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))

	// 将Wei转换为big.Float进行计算
	weiAsFloat := new(big.Float).SetInt(wei)

	// 用Wei除以代币单位得到Ether
	etherValue := new(big.Float).Quo(weiAsFloat, tokenUnit)

	// 将结果转换为字符串，保留小数点后decimals位
	formatStr := fmt.Sprintf("%%.%df", decimals)
	etherValueStr := fmt.Sprintf(formatStr, etherValue)

	return etherValueStr
}

func BigIntDivToString(numerator, denominator *big.Int, numeratorPrec, denominatorPrec, prec uint8, symbol string) (string, error) {
	// 如果分母为0，则返回错误
	if denominator.Cmp(big.NewInt(0)) == 0 {
		return "", fmt.Errorf("denominator分母不能为零")
	}
	if numerator.Cmp(big.NewInt(0)) == 0 {
		return "", fmt.Errorf("numerator分母不能为零")
	}

	// 调整分母的精度，使之与分子的精度相同
	if numeratorPrec > denominatorPrec {
		exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(numeratorPrec-denominatorPrec)), nil)
		denominator = new(big.Int).Mul(denominator, exp)
	} else {
		exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(denominatorPrec-numeratorPrec)), nil)
		numerator = new(big.Int).Mul(numerator, exp)
	}
	var ratNum, ratDenom *big.Rat
	// 将big.Int转换为big.Rat进行计算
	if symbol != "USDT" {
		//如果numerator不是U
		ratNum = new(big.Rat).SetInt(denominator)
		ratDenom = new(big.Rat).SetInt(numerator)
	} else {
		ratNum = new(big.Rat).SetInt(numerator)
		ratDenom = new(big.Rat).SetInt(denominator)
	}

	// 执行除法运算
	ratResult := new(big.Rat).Quo(ratNum, ratDenom)

	// 将结果转换为字符串形式，prec指定小数点后的位数
	resultString := ratResult.FloatString(int(prec))

	return resultString, nil
}

// IsTransferEvent 检查是否为转账事件。
func IsTransferEvent(log *types.Log) bool {
	// 这是Swap事件的签名字符串
	transferEventSignature := []byte("Transfer(address,address,uint256)")
	// 计算签名的Keccak-256哈希
	transferEventHash := crypto.Keccak256Hash(transferEventSignature)
	// 检查日志的第一个Topic是否等于Swap事件的哈希
	return log.Topics[0] == transferEventHash
}

// IsETHTransferEvent 检查是否为自定义的公链币转账事件。
func IsETHTransferEvent(log *types.Log) bool {
	// 公链转账事件
	trabsferETHEventSignature := []byte("Withdraw(address,address,uint256,uint256)")
	// 计算签名的Keccak-256哈希
	transferETHEventHash := crypto.Keccak256Hash(trabsferETHEventSignature)
	// 检查日志的第一个Topic是否等于Swap事件的哈希
	return log.Topics[0] == transferETHEventHash
}

// IsApprovalEvent 检查是否为授权事件。
func IsApprovalEvent(log *types.Log) bool {
	// 这是Swap事件的签名字符串
	signature := []byte("Approval(address,address,uint256)")
	// 计算签名的Keccak-256哈希
	eventHash := crypto.Keccak256Hash(signature)
	// 检查日志的第一个Topic是否等于事件的哈希
	return log.Topics[0] == eventHash
}

// IsSyncEvent 检查是否为Sync事件。
func IsSyncEvent(log *types.Log) bool {
	// 这是Swap事件的签名字符串
	signature := []byte("Sync(uint112,uint112)")
	// 计算签名的Keccak-256哈希
	eventHash := crypto.Keccak256Hash(signature)
	// 检查日志的第一个Topic是否等于事件的哈希
	return log.Topics[0] == eventHash
}

// IsMintEvent 检查是否为Mint事件。
func IsMintEvent(log *types.Log) bool {
	// 这是Swap事件的签名字符串
	signature := []byte("Mint(address,uint256,uint256)")
	// 计算签名的Keccak-256哈希
	eventHash := crypto.Keccak256Hash(signature)
	// 检查日志的第一个Topic是否等于事件的哈希
	return log.Topics[0] == eventHash
}

// IsBurnEvent 检查是否为Burn事件
func IsBurnEvent(log *types.Log) bool {
	// 这是Swap事件的签名字符串
	signature := []byte("Burn(address,uint256,uint256,address)")
	// 计算签名的Keccak-256哈希
	eventHash := crypto.Keccak256Hash(signature)
	// 检查日志的第一个Topic是否等于事件的哈希
	return log.Topics[0] == eventHash
}

// IsDepositEvent 检查是否为Mint事件。
func IsDepositEvent(log *types.Log) bool {
	// 这是Swap事件的签名字符串
	signature := []byte("Deposit(address,uint256)")
	// 计算签名的Keccak-256哈希
	eventHash := crypto.Keccak256Hash(signature)
	// 检查日志的第一个Topic是否等于事件的哈希
	return log.Topics[0] == eventHash
}

//判断加池撤池操作
